// simple regular expressions

#ifndef RS_REGEX_H
#define RS_REGEX_H
#include <vector>
#include "rs_table.h"
#include "rs_string.h"
#include "rs_log.h"
using namespace std;


class regex_charset {
    // characters in regular language as used in rs_regex
    // any subset of 16-bit characters
    // except those used for syntax itself: "[^].$^"
    // todo: check regex_charset not to contain invalid characters
public:
    regex_charset (const rs_string& charset)
        : rcs_charset(charset)
    {
        rcs_size = rcs_charset.size();
    };
    unsigned size() const { return rcs_size; };
    unsigned pos (wchar_t ch) const {
        // position of character in charset
        unsigned p = rcs_charset.find (ch);
        if (p == string::npos)
            return rcs_size;
        else
            return p;
    };
    wchar_t get_char (unsigned pos) const {
        // character at specified position
        if (pos < rcs_size)
            return rcs_charset[pos];
        else
            return L' ';
    };
private:
    rs_string rcs_charset;
    unsigned rcs_size;
};

extern regex_charset lowercase_ascii_letters_charset;
extern regex_charset cmudict_charset;

class rs_regex {
    // simple regular expressions (RE)
    // allowed are bracket conditions like "[aeiou]" or "[^cst]" or "x" or "." 
    // that can occur several times
    // like "[^aeiou].[aeiou]";
    // also "^" and "$" mark start/end of string (if specified fisrt/last in string)
    // not allowed (not specially treated) are star (*), parenthesis "()", etc
    // allowed characters are listed in rsr_charset
    // RE are expected either at end of matching string (rsr_e_fix==true) or at begin (==false)
    // or to be the whole string
    // match end of string: either "is_suffix==true" or end character in "str" is "$"
    // match start of string: 
    // processing is consequently done with deterministic finite automaton (FSA), not yet optimized for speed
public:
    rs_regex (const rs_string& str, 
        const regex_charset* charset=&lowercase_ascii_letters_charset)
        :
        rsr_str (str),
        rsr_charset (charset),
        rsr_s_fix (false),
        rsr_e_fix (false)
    {
        rsr_valid = parse ();
    };
    bool is_valid () const { return rsr_valid; };
    bool matches (const rs_string& str) const;
    const rs_string& get_str () const { return rsr_str; };  // original string
    operator rs_string() const { return stringed_re (); } // compiled version, converted back to string
    unsigned get_length() const { return unsigned (rsr_vec.size()); }
private:
    // variables
    bool rsr_valid;
    bool rsr_s_fix;        // true when "^" is specified as the first character; not yet used
    bool rsr_e_fix;        // true when "$" is specified as the last character
    rs_string rsr_str;         // original RE string
    vector<vector<bool> > rsr_vec;
      // rsr_vec[i][j] is true if character rsr_charset->get_char(j) is allowed at position i
    const regex_charset* rsr_charset;
    // functions
    bool parse ();
    rs_string stringed_re () const;
    bool base_match (const rs_string& str) const;
};

#endif
